/*
 *
 *      Copyright (c) 2018-2025, madp All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the pig4cloud.com developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: 成都文思海辉金信软件有限公司
 *
 */

package com.pactera.madp.admin.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pactera.madp.admin.api.constant.SyncConstant;
import com.pactera.madp.admin.api.constant.UpmsConstant;
import com.pactera.madp.admin.api.dto.UserDTO;
import com.pactera.madp.admin.api.dto.UserInfo;
import com.pactera.madp.admin.api.dto.UserRoleDTO;
import com.pactera.madp.admin.api.entity.*;
import com.pactera.madp.admin.api.feign.RemoteWxService;
import com.pactera.madp.admin.api.vo.MenuVO;
import com.pactera.madp.admin.api.vo.UserVO;
import com.pactera.madp.admin.api.vo.WxEmpVo;
import com.pactera.madp.admin.mapper.SysDeptUserMapper;
import com.pactera.madp.admin.mapper.SysUserMapper;
import com.pactera.madp.admin.service.*;
import com.pactera.madp.common.core.constant.CacheConstants;
import com.pactera.madp.common.core.constant.CommonConstants;
import com.pactera.madp.common.core.constant.SecurityConstants;
import com.pactera.madp.common.core.util.DesensitizedUtils;
import com.pactera.madp.common.core.util.R;
import com.pactera.madp.common.data.datascope.DataScope;
import com.pactera.madp.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author madp
 * @date 2017/10/31
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	private final SysMenuService sysMenuService;
	private final SysRoleService sysRoleService;
	private final SysDeptService sysDeptService;
	private final SysUserRoleService sysUserRoleService;
	private final SysDeptRelationService sysDeptRelationService;
	private final RemoteWxService remoteWxService;
	private final SysDeptUserMapper deptUserMapper;
	private final RedisTemplate redisTemplate;

	/**
	 * 保存用户信息
	 *
	 * @param userDto DTO 对象
	 * @return success/fail
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean saveUser(UserDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
		sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
		baseMapper.insert(sysUser);
		List<SysUserRole> userRoleList = userDto.getRole()
				.stream().map(roleId -> {
					SysUserRole userRole = new SysUserRole();
					userRole.setUserId(sysUser.getUserId());
					userRole.setRoleId(roleId);
					return userRole;
				}).collect(Collectors.toList());
		return sysUserRoleService.saveBatch(userRoleList);
	}

	/**
	 * 通过查用户的全部信息
	 *
	 * @param sysUser 用户
	 * @return
	 */
	@Override
	public UserInfo findUserInfo(SysUser sysUser) {
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		//设置角色列表  （ID）
		//设置角色标识列表
		List<String> roleCodes = new ArrayList<>();
		List<SysRole> roles = sysRoleService.findRolesByUserId(sysUser.getUserId());
		List<Integer> roleIds = roles.stream().map(role -> {
					roleCodes.add(role.getRoleCode());
					return role.getRoleId();
				}).collect(Collectors.toList());
		List<String> roleNames = roles.stream().map(SysRole::getRoleName).collect(Collectors.toList());

		userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));
		userInfo.setRoleCodes(ArrayUtil.toArray(roleCodes, String.class));
		userInfo.setRoleNames(ArrayUtil.toArray(roleNames, String.class));
		Integer deptId = sysUser.getDeptId();
		SysDept dept = sysDeptService.getOne(
				Wrappers.<SysDept>lambdaQuery()
						.select(SysDept::getName)
				.eq(SysDept::getDeptId, deptId)
		);
		userInfo.setDeptName(dept == null ? "" : dept.getName());

		//设置权限列表（menu.permission）
		Set<String> permissions = new HashSet<>();
		roleIds.forEach(roleId -> {
			List<String> permissionList = sysMenuService.findMenuByRoleId(roleId)
					.stream()
					.filter(menuVo -> StringUtils.isNotEmpty(menuVo.getPermission()))
					.map(MenuVO::getPermission)
					.collect(Collectors.toList());
			permissions.addAll(permissionList);
		});
		userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
		return userInfo;
	}

	/**
	 * 分页查询用户信息（含有角色信息）
	 *
	 * @param page    分页对象
	 * @param userDTO 参数列表
	 * @return
	 */
	@Override
	public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
		return baseMapper.getUserVosPage(page, userDTO);
	}

	/**
	 *
	 * @param deptId
	 * @return
	 */
	@Override
	public List<UserVO> getUserVosByDept(Integer deptId) {
		return baseMapper.getUserVosByDept(deptId);
	}

	@Override
	public IPage getUsersWithLineDeptPage(Page page, UserDTO userDTO) {

		return baseMapper.getUsersWithLineDeptPage(page, userDTO);
	}

	/**
	 *
	 * @param deptId
	 * @return
	 */
	@Override
	public List<UserVO> getUsersWithLineDeptByList(Integer deptId) {
		return baseMapper.getUsersWithLineDeptByList(deptId);
	}

	/**
	 * 通过ID查询用户信息
	 *
	 * @param id 用户ID
	 * @return 用户信息
	 */
	@Override
	public UserVO selectUserVoById(Integer id) {
		return baseMapper.getUserVoById(id);
	}

	/**
	 * 删除用户
	 *
	 * @param sysUser 用户
	 * @return Boolean
	 */
	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
	public Boolean deleteUserById(SysUser sysUser) {
		sysUserRoleService.deleteByUserId(sysUser.getUserId());
		this.removeById(sysUser.getUserId());
		return Boolean.TRUE;
	}

	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
	public R<Boolean> updateUserInfo(UserDTO userDto) {
		UserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());
		SysUser sysUser = new SysUser();
		if (StrUtil.isNotBlank(userDto.getPassword())
				&& StrUtil.isNotBlank(userDto.getNewpassword1())) {
			if (ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {
				sysUser.setPassword(ENCODER.encode(userDto.getNewpassword1()));
			} else {
				log.warn("原密码错误，修改密码失败:{}", userDto.getUsername());
				return R.ok(Boolean.FALSE, "原密码错误，修改失败");
			}
		}
		//sysUser.setPhone(userDto.getPhone());
		sysUser.setUserId(userVO.getUserId());
		sysUser.setAvatar(userDto.getAvatar());
		return R.ok(this.updateById(sysUser));
	}

	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
	public Boolean updateUser(UserRoleDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		sysUser.setUpdateTime(LocalDateTime.now());

		if (StrUtil.isNotBlank(userDto.getPassword())) {
			sysUser.setPassword(null);
		}
//		this.updateById(sysUser);
		this.update(
				Wrappers.<SysUser>lambdaUpdate()
						.set(SysUser::getLockFlag, userDto.getLockFlag())
						.eq(SysUser::getUserId, userDto.getUserId())
		);

		sysUserRoleService.remove(Wrappers.<SysUserRole>update().lambda()
				.eq(SysUserRole::getUserId, userDto.getUserId()));
		userDto.getRoleList().forEach(role -> {
			SysUserRole userRole = new SysUserRole();
			userRole.setUserId(sysUser.getUserId());
			userRole.setRoleId(role.getRoleId());
			userRole.insert();
		});
		return Boolean.TRUE;
	}

	/**
	 * 查询上级部门的用户信息
	 *
	 * @param username 用户名
	 * @return R
	 */
	@Override
	public List<SysUser> listAncestorUsers(String username) {
		SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda()
				.eq(SysUser::getUsername, username));

		SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
		if (sysDept == null) {
			return null;
		}

		Integer parentId = sysDept.getParentId();
		return this.list(Wrappers.<SysUser>query().lambda()
				.eq(SysUser::getDeptId, parentId));
	}

	/**
	 * 同步成员数据到系统用户
	 * @param users
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	@Async
	public void onSyncWxEmp(List<SysUser> users) {
		// 系统当前用户列表
		List<SysUser> oldUsers = this.list();

		Map<String,SysUser> usersMap = new HashMap<>();
		users.forEach(u -> usersMap.put(u.getUsername(), u));

		Map<String,SysUser> oldUsersMap = new HashMap<>();
		oldUsers.forEach(u -> oldUsersMap.put(u.getUsername(), u));

		// 新增和更新列表
		List<SysUser> newOrUpdateList = new ArrayList<>();
		// 删除列表
		List<Integer> delList = new ArrayList<>();

		// 过滤新增
		oldUsers.forEach(u -> usersMap.remove(u.getUsername()));
		usersMap.values().forEach(u -> {
			u.setPassword(ENCODER.encode("123456Abc@"));
			newOrUpdateList.add(u);
		});

		// 过滤删除
		users.forEach(u -> {
			// 排除超级管理员
			oldUsersMap.remove("admin");
			SysUser oldUser = oldUsersMap.remove(u.getUsername());
			if (oldUser != null) {
				// 过滤更新
				u.setUserId(oldUser.getUserId());
				u.setPassword(null);
				u.setLockFlag(null);
				newOrUpdateList.add(u);
			}
		});
		oldUsersMap.values().forEach(u -> delList.add(u.getUserId()));

		// 遍历设置主键
		/*for (SysUser user : users) {
			for (SysUser oldUser : oldUsers) {
				if (StrUtil.equals(user.getUsername(), oldUser.getUsername())) {
					user.setUserId(oldUser.getUserId());
					user.setPassword(null);
					user.setLockFlag(null);
					if ("1".equals(user.getDelFlag())) {
						delList.add(user.getUserId());
					}
					break;
				}
			}
			if (user.getUserId() == null) {
				// 设置新增用户初始密码
				user.setPassword(ENCODER.encode("123456Abc@"));
			}
		}
		this.saveOrUpdateBatch(users);*/

		if (!newOrUpdateList.isEmpty()) {
			this.saveOrUpdateBatch(newOrUpdateList);
		}
		if (!delList.isEmpty()) {
			this.removeByIds(delList);
		}
		log.info("批量同步用户成功");
		// 清除缓存
		String dateTempalte = "yyyyMMdd";
		String key = SyncConstant.SYNC_WX_ORG_DEL_LIST + DateUtil.format(new Date(), dateTempalte);
		redisTemplate.delete(key);
		key = SyncConstant.SYNC_WX_SYS_DEL_LIST + DateUtil.format(new Date(), dateTempalte);
		redisTemplate.delete(key);
	}

	/**
	 * 获取当前用户的子部门信息
	 *
	 * @return 子部门列表
	 */
	private List<Integer> getChildDepts() {
		Integer deptId = SecurityUtils.getUser().getDeptId();
		//获取当前部门的子部门
		return sysDeptRelationService
				.list(Wrappers.<SysDeptRelation>query().lambda()
						.eq(SysDeptRelation::getAncestor, deptId))
				.stream()
				.map(SysDeptRelation::getDescendant)
				.collect(Collectors.toList());
	}

	@Override
	public List<Object> selectByRole(Integer roleId) {
		List<Object> userIds = sysUserRoleService.listObjs(Wrappers.<SysUserRole>lambdaQuery().select(SysUserRole::getUserId).eq(SysUserRole::getRoleId, roleId));
		List<Object> phones = this.listObjs(Wrappers.<SysUser>lambdaQuery().select(SysUser::getPhone).in(SysUser::getUserId, userIds));
		return phones;
	}

	@Override
	public List<Map<String, Object>> getUsersWithLineDept(Integer lineDeptId) {
//		List<UserVO> allUsers = this.baseMapper.getUsersWithLineDept(lineDeptId);
		List<SysUser> allUsers = this.baseMapper.getUsersWithLineDept(lineDeptId);
		List<Integer> selectUsers = this.baseMapper.getSelectUsersWithLineDept(lineDeptId);
		List<Map<String, Object>> results = new ArrayList<>();
		allUsers.stream().forEach(s -> {
			Map<String, Object> map = new HashMap<>();
			map.put("userId", s.getUserId());

			R<WxEmpVo> result = remoteWxService.getEmp(s.getPhone(), SecurityConstants.FROM_IN);
			if(result != null && result.getCode() == 0) {
				WxEmpVo wxEmpVo = result.getData();
				map.put("userName", wxEmpVo.getName());
			}
//			map.put("userName", s.getUsername());
			map.put("isSelect", "0");
			inner:
			for (Integer userId : selectUsers) {
				if (s.getUserId() == userId) {
					map.put("isSelect", "1");
					break inner;
				}
			}
			results.add(map);

//			s.setIsSelect("0");
//			inner:
//			for (Integer userId : selectUsers) {
//				if (s.getUserId() == userId) {
//					s.setIsSelect("1");
//					break inner;
//				}
//			}
		});
		return results;
//		return allUsers;
	}

	public IPage getUserPage(String name, Integer deptId, Integer deptType, Page page) {
		if (deptType == UpmsConstant.DEPT_TYPE_LINE) {
			return deptUserMapper.getUserPage(page, deptId, name);
		} else {
			return this.baseMapper.getUserPage(page, deptId, name);
		}
	}

	@Override
	public Boolean resetPwd(Integer userId) {
		return this.update(
				Wrappers.<SysUser>lambdaUpdate()
				.set(SysUser::getPassword, ENCODER.encode("123456Abc!"))
				.eq(SysUser::getUserId, userId)
		);
	}

    @Override
    public IPage getUserPageByObjectId(String name, Integer deptId, Integer deptType, Page page, Integer objectId) {
		if (deptType == UpmsConstant.DEPT_TYPE_LINE) {
			return deptUserMapper.getUserPage(page, deptId, name);
		} else {
			return this.baseMapper.getUserPageByObjectId(page, deptId, name,objectId);
		}
    }

}
